﻿//using System;
//using System.Collections.Generic;
//using System.Data;
//using System.Data.Entity;
//using System.Linq;
//using System.Threading;
//using AutoMapper;
//using UCosmic.Domain;
//using UCosmic.Domain.InstitutionalAgreements;
//using UCosmic.Orm;

//namespace UCosmic.Storage
//{
//    public class InstitutionalAgreementStorage : IStoreInstitutionalAgreements
//    {
//        //#region Construction & DI
//        //
//        //public InstitutionalAgreementStorage(IUnitOfWork unitOfWork)
//        //    : base(unitOfWork)
//        //{
//        //}
//        //
//        //#endregion
//        #region Construction & DI

//        private UCosmicContext DbContext { get; set; }

//        public InstitutionalAgreementStorage(IUnitOfWork unitOfWork)
//        {
//            DbContext = unitOfWork as UCosmicContext;
//        }

//        public IUnitOfWork UnitOfWork { get { return DbContext; } }

//        #endregion
//        #region Search

//        public IEnumerable<InstitutionalAgreement> FindMany(InstitutionalAgreementFinder finder)
//        {
//            // do not track entities returned by find methods
//            var query = DbContext.InstitutionalAgreements.AsQueryable();

//            // initialize finder
//            if (finder == null)
//                finder = new InstitutionalAgreementFinder();

//            // apply context tracking
//            if (!finder.IsForInsertOrUpdate)
//                query = query.AsNoTracking();

//            // apply includes
//            var includes = finder.ToBeEagerLoaded;
//            if (includes != null && includes.Count > 0)
//                query = finder.ToBeEagerLoaded.Aggregate(query, (lastInclude, nextInclude) =>
//                    lastInclude.Include(nextInclude));

//            // apply owner URL
//            if (!string.IsNullOrWhiteSpace(finder.EstablishmentUrl))
//            {
//                query = query.Where(a => 
//                    a.Participants.Any(p => p.IsOwner && 
//                        (finder.EstablishmentUrl.Equals(p.Establishment.WebsiteUrl, StringComparison.OrdinalIgnoreCase)) || 
//                        p.Establishment.Ancestors.Any(h => finder.EstablishmentUrl.Equals(h.Ancestor.WebsiteUrl, StringComparison.OrdinalIgnoreCase))
//                    )
//                );
//            }

//            var found = query.ToList();
//            return found;
//        }

//        #endregion
//        #region Institutional Agreement Aggregate Root

//        private IQueryable<InstitutionalAgreement> All
//        {
//            get { return DbContext.InstitutionalAgreements; }
//        }

//        public IQueryable<InstitutionalAgreement> Current
//        {
//            get
//            {
//                return All
//                    .Include(a => a.Participants)
//                    .Include(a => a.Participants.Select(p => p.Establishment))
//                    .Include(a => a.Participants.Select(p => p.Establishment.Parent))
//                .Current();
//            }
//        }

//        //public override IQueryable<InstitutionalAgreement> AllIncluding(params Expression<Func<InstitutionalAgreement, object>>[] includeProperties)
//        //{
//        //    return includeProperties.Aggregate<Expression<Func<InstitutionalAgreement, object>>, IQueryable<InstitutionalAgreement>>(
//        //        DbContext.InstitutionalAgreements, (current, includeProperty) => current.Include(includeProperty));
//        //}

//        //public InstitutionalAgreement Find(int id)
//        //{
//        //    return DbContext.InstitutionalAgreements.Find(id);
//        //}

//        public void Refresh(InstitutionalAgreement entity)
//        {
//            DbContext.Entry(entity).State = (entity.RevisionId == default(int))
//                ? EntityState.Added
//                : EntityState.Modified;
//        }

//        public InstitutionalAgreement Revise(InstitutionalAgreement revisableEntity)
//        {
//            if (revisableEntity == null) return null;

//            // attach pre-stored files
//            if (revisableEntity.Files != null)
//            {
//                revisableEntity.Files = revisableEntity.Files.Where(oldFile => oldFile.RevisionId != 0)
//                   .Select(oldFile => DbContext.InstitutionalAgreementFiles
//                       .SingleOrDefault(f => f.RevisionId == oldFile.RevisionId))
//                   .Where(newFile => newFile != null).ToList();
//            }

//            // check whether entity already exists in the db
//            var existingEntity = DbContext.InstitutionalAgreements
//                .ByRevisionId(revisableEntity.RevisionId);

//            if (existingEntity == null)
//            {
//                Refresh(revisableEntity);
//                existingEntity = revisableEntity;
//            }
//            else
//            {
//                var existingEntry = DbContext.Entry(existingEntity);
//                existingEntry.CurrentValues.SetValues(revisableEntity);
//                existingEntity.CreatedOnUtc = DateTime.UtcNow;
//                existingEntity.CreatedByPrincipal = Thread.CurrentPrincipal.Identity.Name;
//                var originalEntity = existingEntry.OriginalValues.ToObject() as InstitutionalAgreement;
//                if (originalEntity != null)
//                {
//                    originalEntity.IsCurrent = false;
//                    DbContext.InstitutionalAgreements.Add(originalEntity);
//                }

//                // participants
//                if (revisableEntity.Participants != null)
//                {
//                    var newParticipants = revisableEntity.Participants.ToList();
//                    var oldParticipants = existingEntity.Participants.ToList();
//                    foreach (var oldParticipant in
//                        from oldParticipant in oldParticipants
//                        let matchedParticipant = newParticipants.SingleOrDefault(
//                            p => p.EstablishmentId == oldParticipant.EstablishmentId)
//                        where matchedParticipant == null
//                        select oldParticipant)
//                    {
//                        DbContext.Entry(oldParticipant).State = EntityState.Deleted;
//                    }
//                    foreach (var newParticipant in
//                        from newParticipant in newParticipants
//                        let matchedParticipant = oldParticipants.SingleOrDefault(
//                            p => p.EstablishmentId == newParticipant.EstablishmentId)
//                        where matchedParticipant == null
//                        select newParticipant)
//                    {
//                        existingEntity.Participants.Add(newParticipant);
//                    }
//                    Refresh(existingEntity);
//                }

//                // files
//                if (revisableEntity.Files != null)
//                {
//                    var newFiles = revisableEntity.Files.ToList();
//                    var oldFiles = existingEntity.Files.ToList();
//                    foreach (var oldFile in
//                        from oldFile in oldFiles
//                        let matchedFile = newFiles.SingleOrDefault(
//                            p => p.RevisionId == oldFile.RevisionId)
//                        where matchedFile == null
//                        select oldFile)
//                    {
//                        //DbContext.Entry(oldFile).State = EntityState.Deleted;
//                        oldFile.IsDeleted = true;
//                        oldFile.IsCurrent = false;
//                    }
//                    foreach (var newFile in
//                        from newFile in newFiles
//                        let matchedFile = oldFiles.SingleOrDefault(f => f.RevisionId == newFile.RevisionId)
//                        where matchedFile == null
//                        select newFile)
//                    {
//                        existingEntity.Files.Add(newFile);
//                    }
//                }

//                // contacts
//                if (revisableEntity.Contacts != null)
//                {
//                    var newContacts = revisableEntity.Contacts.ToList();
//                    var oldContacts = existingEntity.Contacts.Current().ToList();
//                    foreach (var oldContact in
//                        from oldContact in oldContacts
//                        let matchedContact = newContacts.SingleOrDefault(
//                            c => c.RevisionId == oldContact.RevisionId)
//                        where matchedContact == null
//                        select oldContact)
//                    {
//                        oldContact.IsDeleted = true;
//                        oldContact.IsCurrent = false;
//                        var changedContact = Mapper.Map<InstitutionalAgreementContact>(oldContact);
//                        changedContact.RevisionId = 0;
//                        changedContact.CreatedOnUtc = DateTime.UtcNow;
//                        changedContact.CreatedByPrincipal = Thread.CurrentPrincipal.Identity.Name;
//                        existingEntity.Contacts.Add(changedContact);
//                    }
//                    foreach (var newContact in
//                        from newContact in newContacts
//                        let matchedContact = oldContacts.SingleOrDefault(
//                            c => c.RevisionId == newContact.RevisionId)
//                        where matchedContact == null
//                        select newContact)
//                    {
//                        existingEntity.Contacts.Add(newContact);
//                    }
//                    Refresh(existingEntity);
//                }

//            }
//            DbContext.Establishments.Load();

//            // enforce derived title
//            existingEntity.Title = (existingEntity.IsTitleDerived)
//                ? existingEntity.DeriveTitle()
//                : existingEntity.Title;

//            DbContext.SaveChanges();
//            RefreshNodeHierarchy();
//            DbContext.SaveChanges();

//            return existingEntity;
//        }

//        #endregion
//        #region Contacts

//        //public IQueryable<InstitutionalAgreementContact> AllContacts
//        //{
//        //    get { return DbContext.InstitutionalAgreementContacts; }
//        //}

//        public IQueryable<InstitutionalAgreementContact> CurrentContacts
//        {
//            get
//            {
//                return DbContext.InstitutionalAgreementContacts.Current();
//            }
//        }

//        #endregion

//        public void RefreshNodeHierarchy()
//        {
//            var agreements = DbContext.InstitutionalAgreements.Current()
//                .Including(e => e.Offspring.Select(o => o.Ancestor.Umbrella))
//                .Including(e => e.Offspring.Select(o => o.Offspring.Umbrella))
//                .Including(e => e.Offspring.Select(o => o.Ancestor.Children))
//                .Including(e => e.Offspring.Select(o => o.Offspring.Children))
//                .Including(e => e.Children.Select(c => c.Children.Select(g => g.Children)))
//                .Including(e => e.Children.Select(c => c.Ancestors.Select(a => a.Ancestor)))
//                .Where(e => e.Umbrella == null && e.Children.Count() > 0);
//            foreach (var parent in agreements)
//            {
//                EmptyAncestryRecursive(parent);
//            }
//            foreach (var parent in agreements)
//            {
//                FillAncestryRecursive(parent);
//            }
//        }

//        private void EmptyAncestryRecursive(InstitutionalAgreement parent)
//        {
//            while (parent.Offspring.FirstOrDefault() != null)
//            {
//                DbContext.Entry(parent.Offspring.FirstOrDefault()).State = EntityState.Deleted;
//            }
//            foreach (var child in parent.Children)
//            {
//                child.Ancestors = child.Ancestors ?? new List<InstitutionalAgreementNode>();
//                while (child.Ancestors.FirstOrDefault() != null)
//                {
//                    DbContext.Entry(child.Ancestors.First()).State = EntityState.Deleted;
//                }
//                EmptyAncestryRecursive(child);
//            }
//        }

//        private static void FillAncestryRecursive(InstitutionalAgreement parent)
//        {
//            foreach (var child in parent.Children.Current())
//            {
//                var node = new InstitutionalAgreementNode
//                {
//                    Ancestor = parent,
//                    Offspring = child,
//                    Separation = 1,
//                };
//                child.Ancestors.Add(node);
//                foreach (var ancestor in parent.Ancestors)
//                {
//                    node = new InstitutionalAgreementNode
//                    {
//                        Ancestor = ancestor.Ancestor,
//                        Offspring = child,
//                        Separation = ancestor.Separation + 1,
//                    };
//                    child.Ancestors.Add(node);
//                }
//                FillAncestryRecursive(child);
//            }
//        }

//        public void Dispose()
//        {
//            UnitOfWork.Dispose();
//        }
//    }

//}